var utility    = require('system/utility'),
	assert     = require('assert'),
	Enumerable = require('collections/enumerable'),
	Linq       = require('collections/linq');

EnumerableTests = (function () {
	var EnumerableTests = function() {
		return {
			'choice': function() {
				var actual = Enumerable.choice(1, 10, 31, 42).take(10).toArray();
				assert.notEqual(actual, [1, 10, 31, 42, 1, 10, 31, 42, 1, 10], 'random test. if failed retry');
				assert.equal(actual.length, 10);

				actual = Enumerable.choice([1, 10, 31, 42]).take(10).toArray();
				assert.notEqual(actual, [1, 10, 31, 42, 1, 10, 31, 42, 1, 10], 'random test. if failed retry');
				assert.equal(actual.length, 10);
			},
			'cycle': function() {
				var actual = Enumerable.cycle(1, 10, 31, 42).take(10).toArray();
				assert.deepEqual(actual, [1, 10, 31, 42, 1, 10, 31, 42, 1, 10]);
				actual = Enumerable.cycle([1, 2, 3, 4, 5]).take(10).toArray();
				assert.deepEqual(actual, [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]);
			},
			'empty': function() {
				var actual = Enumerable.empty().toArray();
				assert.deepEqual(actual, []);
			},
			'asEnumerable': function() {
				var actual = 'temp'.asEnumerable().toArray();
				assert.deepEqual(actual, ['t', 'e', 'm', 'p']);

				actual = (3).asEnumerable().toArray();
				assert.deepEqual(actual, [3]);

				actual = [1, 2, 3, 4, 5].asEnumerable().toArray();
				assert.deepEqual(actual, [1, 2, 3, 4, 5]);

				actual = Object.asEnumerable({ foo: 'bar', func: function() { } }).toArray();
				assert.deepEqual(actual, [{ key: 'foo', value: 'bar'}]);

				if (utility.isBrowser()) {
					var div = document.createElement('html');
					var last = document.createElement('div');

					last.appendChild(document.createTextNode('test'));
					div.appendChild(document.createElement('div'));
					div.appendChild(document.createElement('div'));
					div.appendChild(last);

					var seq = div.getElementsByTagName('div').asEnumerable();
					assert.equal(seq.count(), 3);
					assert.equal(seq.elementAt(2), last);
					assert.equal(seq.elementAt(2).firstChild.nodeValue, 'test');
				}
			},
			'select': function() {
				var actual = Enumerable.range(1, 10).select('i=>i*10').toArray();
				assert.deepEqual(actual, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
				actual = Enumerable.range(1, 10).select('i,index=>i*10+index').toArray();
				assert.deepEqual(actual, [10, 21, 32, 43, 54, 65, 76, 87, 98, 109]);
			},
			'Return': function() {
				var actual = Enumerable.Return('hoge').toArray();
				assert.deepEqual(actual, ['hoge']);
			},
			'matches': function() {
				var actual = Enumerable.matches('xbcyBCzbc', /(.)bc/i).select('$.index+$[1]').toArray();
				assert.deepEqual(actual, ['0x', '3y', '6z']);
				actual = Enumerable.matches('xbcyBCzbc', '(.)bc').select('$.index+$[1]').toArray(); ;
				assert.deepEqual(actual, ['0x', '6z']);
				actual = Enumerable.matches('xbcyBCzbc', '(.)bc', 'i').select('$.index+$[1]').toArray(); ;
				assert.deepEqual(actual, ['0x', '3y', '6z']);
			},
			'range': function() {
				var actual = Enumerable.range(1, 10).toArray();
				assert.deepEqual(actual, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
				actual = Enumerable.range(1, 5, 3).toArray();
				assert.deepEqual(actual, [1, 4, 7, 10, 13]);
			},
			'rangeDown': function() {
				var actual = Enumerable.rangeDown(1, 10).toArray();
				assert.deepEqual(actual, [1, 0, -1, -2, -3, -4, -5, -6, -7, -8]);
				actual = Enumerable.rangeDown(1, 5, 3).toArray();
				assert.deepEqual(actual, [1, -2, -5, -8, -11]);
			},
			'rangeTo': function() {
				var actual = Enumerable.rangeTo(5, 10).toArray();
				assert.deepEqual(actual, [5, 6, 7, 8, 9, 10]);
				actual = Enumerable.rangeTo(1, 10, 3).toArray();
				assert.deepEqual(actual, [1, 4, 7, 10]);
				actual = Enumerable.rangeTo(-2, -8).toArray();
				assert.deepEqual(actual, [-2, -3, -4, -5, -6, -7, -8]);
				actual = Enumerable.rangeTo(-2, -8, 2).toArray();
				assert.deepEqual(actual, [-2, -4, -6, -8]);
			},
			'repeat': function() {
				var actual = Enumerable.repeat('temp').take(3).toArray();
				assert.deepEqual(actual, ['temp', 'temp', 'temp']);
				actual = Enumerable.repeat('temp', 5).toArray();
				assert.deepEqual(actual, ['temp', 'temp', 'temp', 'temp', 'temp']);
			},
			'repeatWithFinalize': function() {
				var fin;
				var actual = Enumerable.repeatWithFinalize(
								function() { return 'temp'; },
								function() { fin = 'final'; })
							.take(3).toArray();
				assert.deepEqual(actual, ['temp', 'temp', 'temp']);
				assert.equal('final', fin);
			},
			'generate': function() {
				var actual = Enumerable.generate(function() { return 'temp' }).take(3).toArray();
				assert.deepEqual(actual, ['temp', 'temp', 'temp']);
				actual = Enumerable.generate(function() { return 'temp' }, 5).toArray();
				assert.deepEqual(actual, ['temp', 'temp', 'temp', 'temp', 'temp']);
			},
			'toInfinity': function() {
				var actual = Enumerable.toInfinity().where('i=>i%2==0').take(10).toArray();
				assert.deepEqual(actual, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
				actual = Enumerable.toInfinity(101).take(5).toArray();
				assert.deepEqual(actual, [101, 102, 103, 104, 105]);
				actual = Enumerable.toInfinity(101, 5).take(5).toArray();
				assert.deepEqual(actual, [101, 106, 111, 116, 121]);
			},
			'toNegativeInfinity': function() {
				var actual = Enumerable.toNegativeInfinity().where('i=>i%2==0').take(10).toArray();
				assert.deepEqual(actual, [0, -2, -4, -6, -8, -10, -12, -14, -16, -18]);
				actual = Enumerable.toNegativeInfinity(3).take(10).toArray();
				assert.deepEqual(actual, [3, 2, 1, 0, -1, -2, -3, -4, -5, -6]);
				actual = Enumerable.toNegativeInfinity(3, 5).take(4).toArray();
				assert.deepEqual(actual, [3, -2, -7, -12]);
			},
			'unfold': function() {
				var actual = Enumerable.unfold(5, '$+3').take(5).toArray();
				assert.deepEqual(actual, [5, 8, 11, 14, 17]);
			}
		}
	};

	return EnumerableTests;
})();

// Hook into commonJS module systems
if (typeof module !== 'undefined' && "exports" in module) {
  module.exports = EnumerableTests;
}